package org.iks.common.util;

import cn.hutool.core.codec.Base64;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * Author kzou
 * Date 2024/1/7 9:15
 * Description: RAS 加密 工具类
 */
public class RSAUtil {

    private static final String algorithm = "RSA";

    public static String parsePem(String pemKeyStr) {
        String result = "";
        if (pemKeyStr.contains("-")) {
            String[] strings = pemKeyStr.split("-");
            for (String item : strings) {
                if (item.length() >result.length()) {
                    result = item;
                }
            }
        }
        return result;
    }

    /**
     * pem 格式
     * -----BEGIN PUBLIC KEY-----
     * MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfg9h9ixVwaLiW/cdY0Rk/lvG6
     * mJc7zD4A4uJLq....
     * -----END PUBLIC KEY-----
     *
     * @param publicKey pem 格式的公钥
     * @return PublicKey
     * @throws Exception e
     */
    public static PublicKey getPublicKeyFromPem(String publicKey) throws Exception {
        boolean isPkcs1 = publicKey.toLowerCase().contains("rsa");
        if (publicKey.contains("-")) {
            publicKey = parsePem(publicKey);
        }
        byte[] decode = Base64.decode(publicKey);
        if (isPkcs1) {
            return pkcs1To8ByPublicKey(decode);
        }
        return getPublicKey(decode);
    }
    public static PrivateKey getPrivateFromPem(String privateKey) throws Exception {
        boolean isPkcs1 = privateKey.toLowerCase().contains("rsa");
        if (privateKey.contains("-")) {
            privateKey = parsePem(privateKey);
        }
        byte[] decode = Base64.decode(privateKey);
        if (isPkcs1) {
            return pkcs1To8ByPrivateKey(decode);
        }
        return getPrivateKey(decode);
    }

    public static PrivateKey getPrivateKey(byte[] pkcs8PrivateKey) throws Exception {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8PrivateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        return keyFactory.generatePrivate(keySpec);
    }

    public static PublicKey getPublicKey(byte[] pkcs8PublicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pkcs8PublicKey);
        return keyFactory.generatePublic(x509EncodedKeySpec);
    }

    public static byte[] encode(Key key, String data) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
    }

    public static byte[] encode(Key key, byte[] data) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data);
    }

    public static byte[] decode(Key key, byte[] data) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(data);
    }

    /**
     * 将 pkcs1 格式的公钥 转为 pkcs8 格式
     *
     * @param key pkcs1 格式的公钥
     * @return pkcs8 格式的公钥
     * @throws Exception e
     */
    public static PublicKey pkcs1To8(PublicKey key) throws Exception {
        byte[] pkEncoded = key.getEncoded();
        return pkcs1To8ByPublicKey(pkEncoded);
    }

    /**
     * 将 pkcs1 格式的公钥 转为 pkcs8 格式
     *
     * @param key pkcs1 格式的公钥
     * @return pkcs8 格式的公钥
     * @throws Exception e
     */
    public static PublicKey pkcs1To8ByPublicKey(byte[] key) throws Exception {
        KeyFactory kf = KeyFactory.getInstance(algorithm);
        org.bouncycastle.asn1.pkcs.RSAPublicKey rsaPub = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(key);
        RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(rsaPub.getModulus(), rsaPub.getPublicExponent());
        return kf.generatePublic(rsaPublicKeySpec);
    }

    /**
     * 将 pkcs1 格式的私钥 转为 pkcs8 格式
     *
     * @param key pkcs1 格式的私钥
     * @return pkcs8 格式的私钥
     * @throws Exception e
     */
    public static PrivateKey pkcs1To8(PrivateKey key) throws Exception {
        byte[] keyEncoded = key.getEncoded();
        return pkcs1To8ByPrivateKey(keyEncoded);
    }

    /**
     * 将 pkcs1 格式的私钥 转为 pkcs8 格式
     *
     * @param key pkcs1 格式的私钥
     * @return pkcs8 格式的私钥
     * @throws Exception e
     */
    public static PrivateKey pkcs1To8ByPrivateKey(byte[] key) throws Exception {
        org.bouncycastle.asn1.pkcs.RSAPrivateKey privateKey = org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(key);
        KeyFactory kf = KeyFactory.getInstance(algorithm);
        RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(privateKey.getModulus(), privateKey.getPrivateExponent());
        return kf.generatePrivate(rsaPrivateKeySpec);
    }


}
